﻿
using EmperialApps.WeatherSpark.Data;
using EmperialApps.WeatherSpark.Helpers;
using EmperialApps.WeatherSpark.Internal;
using EmperialApps.WeatherSpark.Resources;
using Microsoft.Phone.Shell;
using System;
using System.Windows.Media;
using System.Windows.Navigation;

namespace EmperialApps.WeatherSpark {

    public partial class DetailPage : ForecastPage {

        private static readonly Brush GrayBrush = new SolidColorBrush( Colors.Gray );

        private readonly IApplicationBar _appBar;
        private readonly ApplicationBarIconButton _lineIconButton;
        private readonly ApplicationBarIconButton _refreshIconButton;
        private readonly ApplicationBarIconButton _forwardIconButton;
        private readonly ApplicationBarIconButton _backwardIconButton;
        private readonly TrialManager _trial;
        private bool _graphLoaded;


        public DetailPage( ) {
            typeof( DetailPage ).Log( "Initializing" );
            InitializeComponent( );

            this.Graph.MovementCapabilityChanged += this.OnGraphMovementCapabilityChanged;
            this.Graph.MoveComplete += this.OnGraphMoveCompleted;

            this._appBar = this.ApplicationBar;
            this._lineIconButton = this._appBar.AddIconButton( Localized.Button.follow, this.OnFollowClicked, isEnabled: true );
            this._refreshIconButton = this._appBar.AddIconButton( Localized.Button.refresh, this.OnRefreshClicked, isEnabled: false );
            this._backwardIconButton = this._appBar.AddIconButton( Localized.Button.backward, this.OnDirectionClicked, isEnabled: false );
            this._forwardIconButton = this._appBar.AddIconButton( Localized.Button.forward, this.OnDirectionClicked, isEnabled: false );
            if( Settings.Current != null )
                this.InitializeWithCurrentSettings( );

            this._trial = new TrialManager( this ) { AdContainer = this.AdContainer };

            // Fix size after initial display, to prevent unnecessary layout during transition effects.
            this.SizeChanged += delegate {
                this.Width = this.ActualWidth;
                this.MaxHeight = this.ActualHeight;
            };
        }


        private bool Communicating {
            get { return !this._refreshIconButton.IsEnabled; }
            set { this._refreshIconButton.IsEnabled = !value; }
        }


        protected override void OnNavigatedTo( NavigationEventArgs e ) {
            base.OnNavigatedTo( e );
            LittleWatson.CheckForPreviousException( );

            string tileIdInput;
            if( Settings.Current == null && this.NavigationContext.QueryString.TryGetValue( LocationSettings.TileIdPropertyName, out tileIdInput ) ) {
                typeof( DetailPage ).Log( "- Parsing tile ID from query string '" + tileIdInput + "'" );
                int tileId = int.Parse( tileIdInput );

                Settings.Current = LocationSettings.TryFind( tileId );
                if( Settings.Current == null ) {
                    LocationSettings.RemoveTile( tileId );
                    this.NavigationService.Navigate( Settings.ChooseLocationPage );
                    return;
                }

                this.InitializeWithCurrentSettings( );
            }
            else if( this.EnsureCurrentSettings( fallback: true ) ) {
                this.InitializeWithCurrentSettings( );
            }

            this.Graph.DisplayLevel = Settings.Current.GetDetailPageLevel( );
            this.Graph.Units = Settings.Current.Units;
            this.Graph.ShowExtremesUsingNight = Settings.Current.NightExtremes;
            this.Graph.Nickname = Settings.Current.GetDisplayName( );

            this.UpdateReferenceLine( Settings.Current.FollowingReferenceLine );
            this.Update( Settings.Current.DownloadUri );
            Settings.Current.UpdateTile( this.TileProgress, TileUpdateReason.Refresh );
        }

        protected override void OnNavigatedFrom( NavigationEventArgs e ) {
            typeof( DetailPage ).Log( "Leaving" );
            base.OnNavigatedFrom( e );

            this._trial.Clear( );
        }


        private void InitializeWithCurrentSettings( ) {
            int index = Settings.Current.GetIndex( );
            this._appBar.AddMenuItem( Localized.Menu.settings, this.NavigateTo( Settings.SettingsPage, index ) );
            this._appBar.AddMenuItem( Localized.Menu.about, this.NavigateTo( Settings.AboutPage ) );
        }

        private void Update( string downloadUri ) {
            int index = Settings.Current.GetIndex( );
            typeof( DetailPage ).Log( "Updating forecast " + index );
            this._trial.Update( );

            if( this._graphLoaded )
                this.BeginDownload( downloadUri );

            Forecast forecast;
            Exception error;
            if( Settings.Current.Location.TryLoadForecast( typeof( DetailPage ), index, out forecast, out error ) ) {
                this.DisplayForecast( forecast );
            }
            else {
                if( !Downloading )
                    this.BeginDownload( downloadUri );

                if( error != null )
                    error.Report( Localized.ErrorSource.Loading );
            }
        }

        private void BeginDownload( string downloadUri, DownloadReason reason = DownloadReason.AutoRefresh ) {
            this.Communicating = true;
            if( !this.BeginForecastDownload( Settings.Current, downloadUri, reason ) )
                this.OnForecastDownloadComplete( null );
        }

        protected override void OnForecastDownloadComplete( ForecastEventArgs e ) {
            this.DisplayForecast( this.Forecast );
            this.Communicating = false;
        }

        private void DisplayForecast( Forecast forecast ) {
            if( forecast != null )
                this.Graph.Forecast = forecast;
        }

        private void UpdateReferenceLine( bool followingReferenceLine ) {
            Settings.Current.FollowingReferenceLine = followingReferenceLine;
            this.Graph.FollowingReferenceLine = followingReferenceLine;

            string name = followingReferenceLine ? "following" : "follow";
            this._lineIconButton.SetIcon( name );
        }


        private void OnGraphMoveCompleted( object sender, EventArgs e ) {
            if( !this._graphLoaded ) {
                this._graphLoaded = true;
                this.BeginDownload( Settings.Current.DownloadUri );
                Settings.UpdateTileAgent( );
            }
        }

        private void OnGraphMovementCapabilityChanged( object sender, EventArgs e ) {
            this._forwardIconButton.IsEnabled = this.Graph.CanMoveForward;
            this._backwardIconButton.IsEnabled = this.Graph.CanMoveBackward;
        }

        private void OnDirectionClicked( object sender, EventArgs e ) {
            bool forward = sender == this._forwardIconButton;
            this.Graph.Move( forward );
        }

        private void OnRefreshClicked( object sender, EventArgs e ) {
            this.BeginDownload( Settings.Current.DownloadUri, DownloadReason.ManualRefresh );
        }

        private void OnFollowClicked( object sender, EventArgs e ) {
            this.UpdateReferenceLine( !Settings.Current.FollowingReferenceLine );
        }

    }

}
